home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / linux / tools / gtar10.lha / diffarch.c < prev    next >
C/C++ Source or Header  |  1992-09-09  |  15KB  |  687 lines

  1. /* Diff files from a tar archive.
  2.    Copyright (C) 1988 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * Diff files from a tar archive.
  22.  *
  23.  * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
  24.  *
  25.  * @(#) diffarch.c 1.10 87/11/11 - gnu
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32.  
  33. #ifdef BSD42
  34. #include <sys/file.h>
  35. #endif
  36.  
  37. #ifndef MSDOS
  38. #include <sys/ioctl.h>
  39. #if (!defined(USG) || defined(HAVE_MTIO)) && !defined(amigados)
  40. #include <sys/mtio.h>
  41. #endif
  42. #endif
  43.  
  44. #ifdef USG
  45. #include <fcntl.h>
  46. #endif
  47.  
  48. /* Some systems don't have these #define's -- we fake it here. */
  49. #ifndef O_RDONLY
  50. #define    O_RDONLY    0
  51. #endif
  52. #ifndef    O_NDELAY
  53. #define    O_NDELAY    0
  54. #endif
  55.  
  56. #ifndef S_IFLNK
  57. #define lstat stat
  58. #endif
  59.  
  60. extern int errno;            /* From libc.a */
  61. extern char *valloc();            /* From libc.a */
  62.  
  63. #include "tar.h"
  64. #include "port.h"
  65. #include "rmt.h"
  66.  
  67. extern union record *head;        /* Points to current tape header */
  68. extern struct stat hstat;        /* Stat struct corresponding */
  69. extern int head_standard;        /* Tape header is in ANSI format */
  70.  
  71. extern void print_header();
  72. extern void skip_file();
  73. extern void skip_extended_headers();
  74.  
  75. extern FILE *msg_file;
  76.  
  77. int now_verifying = 0;        /* Are we verifying at the moment? */
  78.  
  79. int    diff_fd;        /* Descriptor of file we're diffing */
  80.  
  81. char    *diff_buf = 0;        /* Pointer to area for reading
  82.                        file contents into */
  83.  
  84. char    *diff_dir;        /* Directory contents for LF_DUMPDIR */
  85.  
  86. int different = 0;
  87.  
  88. /*struct sp_array *sparsearray;
  89. int         sp_ar_size = 10;*/
  90. /*
  91.  * Initialize for a diff operation
  92.  */
  93. diff_init()
  94. {
  95.  
  96.     /*NOSTRICT*/
  97.     diff_buf = (char *) valloc((unsigned)blocksize);
  98.     if (!diff_buf) {
  99.         msg("could not allocate memory for diff buffer of %d bytes",
  100.             blocksize);
  101.         exit(EX_ARGSBAD);
  102.     }
  103. }
  104.  
  105. /*
  106.  * Diff a file against the archive.
  107.  */
  108. void
  109. diff_archive()
  110. {
  111.     register char *data;
  112.     int check, namelen;
  113.     int err;
  114.     long offset;
  115.     struct stat filestat;
  116.     int compare_chunk();
  117.     int compare_dir();
  118. #ifndef __MSDOS__
  119.     dev_t    dev;
  120.     ino_t    ino;
  121. #endif
  122.     char *get_dir_contents();
  123.     long from_oct();
  124.     long lseek();
  125.  
  126.     errno = EPIPE;            /* FIXME, remove perrors */
  127.  
  128.     saverec(&head);            /* Make sure it sticks around */
  129.     userec(head);            /* And go past it in the archive */
  130.     decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  131.  
  132.     /* Print the record from 'head' and 'hstat' */
  133.     if (f_verbose) {
  134.         if(now_verifying)
  135.             fprintf(msg_file,"Verify ");
  136.         print_header();
  137.     }
  138.  
  139.     switch (head->header.linkflag) {
  140.  
  141.     default:
  142.         msg("Unknown file type '%c' for %s, diffed as normal file",
  143.             head->header.linkflag, head->header.name);
  144.         /* FALL THRU */
  145.  
  146.     case LF_OLDNORMAL:
  147.     case LF_NORMAL:
  148.     case LF_SPARSE:
  149.     case LF_CONTIG:
  150.         /*
  151.          * Appears to be a file.
  152.          * See if it's really a directory.
  153.          */
  154.         namelen = strlen(head->header.name)-1;
  155.         if (head->header.name[namelen] == '/')
  156.             goto really_dir;
  157.  
  158.         
  159.         if(do_stat(&filestat)) {
  160.             if (head->header.isextended)
  161.                 skip_extended_headers();
  162.             skip_file((long)hstat.st_size);
  163.             different++;
  164.             goto quit;
  165.         }
  166.  
  167.         if ((filestat.st_mode & S_IFMT) != S_IFREG) {
  168.             fprintf(msg_file, "%s: not a regular file\n",
  169.                 head->header.name);
  170.             skip_file((long)hstat.st_size);
  171.             different++;
  172.             goto quit;
  173.         }
  174.  
  175.         filestat.st_mode &= ~S_IFMT;
  176.         if (filestat.st_mode != hstat.st_mode)
  177.             sigh("mode");
  178.         if (filestat.st_uid  != hstat.st_uid)
  179.             sigh("uid");
  180.         if (filestat.st_gid  != hstat.st_gid)
  181.             sigh("gid");
  182.         if (filestat.st_mtime != hstat.st_mtime)
  183.             sigh("mod time");
  184.         if (head->header.linkflag != LF_SPARSE &&
  185.                 filestat.st_size != hstat.st_size) {
  186.             sigh("size");
  187.             skip_file((long)hstat.st_size);
  188.             goto quit;
  189.         }
  190.  
  191.         diff_fd = open(head->header.name, O_NDELAY|O_RDONLY);
  192.  
  193.         if (diff_fd < 0 && !f_absolute_paths) {
  194.             char tmpbuf[NAMSIZ+2];
  195.  
  196.             tmpbuf[0]='/';
  197.             strcpy(&tmpbuf[1],head->header.name);
  198.             diff_fd=open(tmpbuf, O_NDELAY|O_RDONLY);
  199.         }
  200.         if (diff_fd < 0) {
  201.             msg_perror("cannot open %s",head->header.name);
  202.             if (head->header.isextended)
  203.                 skip_extended_headers();
  204.             skip_file((long)hstat.st_size);
  205.             different++;
  206.             goto quit;
  207.         }
  208.         /*
  209.          * Need to treat sparse files completely differently here.
  210.          */
  211.         if (head->header.linkflag == LF_SPARSE)
  212.             diff_sparse_files(hstat.st_size);
  213.         else 
  214.             wantbytes((long)(hstat.st_size),compare_chunk);
  215.  
  216.         check = close(diff_fd);
  217.         if (check < 0)
  218.             msg_perror("Error while closing %s",head->header.name);
  219.  
  220.     quit:
  221.         break;
  222.  
  223. #ifndef __MSDOS__
  224.     case LF_LINK:
  225.         if(do_stat(&filestat))
  226.             break;
  227.         dev = filestat.st_dev;
  228.         ino = filestat.st_ino;
  229.         err = stat(head->header.linkname, &filestat);
  230.         if (err < 0) {
  231.             if (errno==ENOENT) {
  232.                 fprintf(msg_file, "%s: does not exist\n",head->header.name);
  233.             } else {
  234.                 msg_perror("cannot stat file %s",head->header.name);
  235.             }
  236.             different++;
  237.             break;
  238.         }
  239.         if(filestat.st_dev!=dev || filestat.st_ino!=ino) {
  240.             fprintf(msg_file, "%s not linked to %s\n",head->header.name,head->header.linkname);
  241.             break;
  242.         }
  243.         break;
  244. #endif
  245.  
  246. #ifdef S_IFLNK
  247.     case LF_SYMLINK:
  248.     {
  249.         char linkbuf[NAMSIZ+3];
  250.         check = readlink(head->header.name, linkbuf,
  251.                  (sizeof linkbuf)-1);
  252.         
  253.         if (check < 0) {
  254.             if (errno == ENOENT) {
  255.                 fprintf(msg_file,
  256.                     "%s: no such file or directory\n",
  257.                     head->header.name);
  258.             } else {
  259.                 msg_perror("cannot read link %s",head->header.name);
  260.             }
  261.             different++;
  262.             break;
  263.         }
  264.  
  265.         linkbuf[check] = '\0';    /* Null-terminate it */
  266.         if (strncmp(head->header.linkname, linkbuf, check) != 0) {
  267.             fprintf(msg_file, "%s: symlink differs\n",
  268.                 head->header.linkname);
  269.             different++;
  270.         }
  271.     }
  272.         break;
  273. #endif
  274.  
  275.     case LF_CHR:
  276.         hstat.st_mode |= S_IFCHR;
  277.         goto check_node;
  278.  
  279. #ifdef S_IFBLK
  280.     /* If local system doesn't support block devices, use default case */
  281.     case LF_BLK:
  282.         hstat.st_mode |= S_IFBLK;
  283.         goto check_node;
  284. #endif
  285.  
  286. #ifdef S_IFIFO
  287.     /* If local system doesn't support FIFOs, use default case */
  288.     case LF_FIFO:
  289.         hstat.st_mode |= S_IFIFO;
  290.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  291.         goto check_node;
  292. #endif
  293.  
  294.     check_node:
  295.         /* FIXME, deal with umask */
  296.         if(do_stat(&filestat))
  297.             break;
  298.         if(hstat.st_rdev != filestat.st_rdev) {
  299.             fprintf(msg_file, "%s: device numbers changed\n", head->header.name);
  300.             different++;
  301.             break;
  302.         }
  303.         if(hstat.st_mode != filestat.st_mode) {
  304.             fprintf(msg_file, "%s: mode or device-type changed\n", head->header.name);
  305.             different++;
  306.             break;
  307.         }
  308.         break;
  309.  
  310.     case LF_DUMPDIR:
  311.         data=diff_dir=get_dir_contents(head->header.name,0);
  312.         wantbytes((long)(hstat.st_size),compare_dir);
  313.         free(data);
  314.         /* FALL THROUGH */
  315.  
  316.     case LF_DIR:
  317.         /* Check for trailing / */
  318.         namelen = strlen(head->header.name)-1;
  319.     really_dir:
  320.         while (namelen && head->header.name[namelen] == '/')
  321.             head->header.name[namelen--] = '\0';    /* Zap / */
  322.  
  323.         if(do_stat(&filestat))
  324.             break;
  325.         if((filestat.st_mode&S_IFMT)!=S_IFDIR) {
  326.             fprintf(msg_file, "%s is no longer a directory\n",head->header.name);
  327.             different++;
  328.             break;
  329.         }
  330.         if((filestat.st_mode&~S_IFMT) != hstat.st_mode)
  331.             sigh("mode");
  332.         break;
  333.  
  334.     case LF_VOLHDR:
  335.         break;
  336.  
  337.     case LF_MULTIVOL:
  338.         namelen = strlen(head->header.name)-1;
  339.         if (head->header.name[namelen] == '/')
  340.             goto really_dir;
  341.  
  342.         if(do_stat(&filestat))
  343.             break;
  344.  
  345.         if ((filestat.st_mode & S_IFMT) != S_IFREG) {
  346.             fprintf(msg_file, "%s: not a regular file\n",
  347.                 head->header.name);
  348.             skip_file((long)hstat.st_size);
  349.             different++;
  350.             break;
  351.         }
  352.  
  353.         filestat.st_mode &= ~S_IFMT;
  354.         offset = from_oct(1+12, head->header.offset);
  355.         if (filestat.st_size != hstat.st_size + offset) {
  356.             sigh("size");
  357.             skip_file((long)hstat.st_size);
  358.             different++;